import datetime
import json
import random
import uuid
from faker import Faker
fake = Faker('zh_CN')

def generate_address():
    return fake.address()


from flask import Flask, Response, render_template, request
# from flask_cors import CORS
import psycopg2
from psycopg2 import extras

txt = '常用汉字'
with open('static/txt/四世同堂.txt', 'r', encoding='utf8') as f:
    txt = f.read()
length = len(txt)-1
page_count = 10
question_count = 10
app = Flask(__name__, static_folder='static')
# CORS(app)

# 模拟数据
mock_data = [
    [
       {'label':'x',"value":"示例值"},
       {'label':'y',"value":"示例值"},
       {'label':'z',"value":"上海","type":"select", "options":["北京", "上海", "广州", "深圳"]},
       {'label':'g',"value":"工程师"},
    ],
    [
        {'label':'x',"value":"aaa"},
        {'label':'y',"value":"98"},
        {'label':'z',"value":"深圳","type":"select", "options":["北京", "上海", "广州", "深圳"]},
        {'label':'g',"value":"工人"},
    ]
]
conn_kw = dict(database='postgres',
    host='localhost',
    port=5432,
    user='postgres',
    password='123456789')

@app.route('/')
def home():
    return render_template('index.html')

@app.route('/page_b.html')
def page_b(*args,**kw):
    return render_template('form.html')

def table_exists(cr, tablename):
    """ Return whether the given table exists. """
    try:
        cr.execute(f'select 1 from {tablename} limit 1')
    except:
        cr.execute('rollback')
        return False
    return True
def execute(sql, args, return_one=False, return_many=False, commit=False):
    cr = conn = None
    try:
        conn = psycopg2.connect(**conn_kw); cr = conn.cursor(cursor_factory=extras.RealDictCursor)
        cr.execute(sql, args)
        if return_one:
            return cr.fetchone()
        elif return_many:
            return cr.fetchall()
        if commit:
            cr.execute('commit')
    finally:
        if cr:
            cr.close()
        if conn:
            conn.close()
def GBK2312():
    0x4e00, 0x9fff
    head = random.randint(0xb0, 0xf7)
    body = random.randint(0xa1, 0xfe)
    val = f'{head:x} {body:x}'
    str = bytes.fromhex(val).decode('gb2312')
    return str
def is_hanzi(c):
    if '\u4e00' <= c <= '\u9fff':
        return True
    if '\u3400' <= c <= '\u4DBF':
        return True
    if '\u20000' <= c <= '\u2A6DF':
        return True
    if '\u2A700' <= c <= '\u2B73F':
        return True
    if '\u2B740' <= c <= '\u2B81F':
        return True
    if '\u2B820' <= c <= '\u2CEAF':
        return True
    if '\u2CEB0' <= c <= '\u2EBEF':
        return True
    if '\u30000' <= c <= '\u3134F':
        return True
def hanzi():
    i = random.randint(0, length)
    c = txt[i]
    while not is_hanzi(c):
        i = random.randint(0, length)
        c = txt[i]
    return c
def get_month():
    return str(random.randint(100, 2050)).rjust(4,'0')+'-'+str(random.randint(1, 12))
def get_random_question():
    res = []
    templates = ['姓名']*1 + ['地址']*1 + ['卡号']*3 + ['证号']*5 + ['选项']*2+['日期']*1
    templates =  ['卡号']*5 + ['证号']*5 
    random.shuffle(templates)
    for index, i in enumerate(templates):
        ttype = 'input'
        options = []
        label = i
        if i == '姓名':
            item = hanzi()+hanzi()+hanzi()
        elif i == '地址':
            item = generate_address()
        elif i == '卡号':
            item=''.join(str(random.randint(0,9)) for i in range(0,18))
        elif i == '证号':
            item=''.join(str(random.randint(0,9)) for i in range(0,random.randint(16,19)))
        elif i == '选项':
            ttype='select'
            rint = random.randint(1,3)
            mod3 = rint%3
            if  mod3 == 0:
                label='地址'
                options = [generate_address(),generate_address(),generate_address(),generate_address()]; 
            elif mod3 == 1:
                label='性别'
                options = ['男','女','保密','跨性别']
            elif mod3 == 2:
                label='年月'
                options = [get_month(),get_month(),get_month(),get_month(),get_month()]

            item = options[0]
            random.shuffle(options)
        elif i == '日期':
            item=get_month()+'-'+str(random.randint(1,30)).rjust(2,'0')
        label+=f'_{index}'
        res.append({'label': label, 'value': item, 'type':ttype, 'options': options})
    return res

def gen_data(cr):
    if not table_exists(cr, 'question'):
        cr.execute('create table question (id varchar(50), content text)')
        cr.execute('create table answer (id varchar(50), question_id varchar(50), question_index int4,  content text, create_date timestamp)')
        cr.execute('create table result (id varchar(50), question_id varchar(50), create_date timestamp, mis_content text, total int4, mistake int4)')
    rec_id = uuid.uuid4().hex
    cr.execute('''
        insert into question values (%s,%s)
    ''', (rec_id, json.dumps([get_random_question() for i in range(page_count)],ensure_ascii=False)))
    cr.execute('commit')
    return rec_id

@app.route('/get_question_id', methods=['GET'])
def get_question_id():
    """获取问题数据接口"""
    rec_id = None
    cr = conn = None
    try:
        conn = psycopg2.connect(**conn_kw); cr = conn.cursor(cursor_factory=extras.RealDictCursor)
        rec_id = gen_data(cr)
    finally:
        if cr:
            cr.close()
        if conn:
            conn.close()
    res = Response(json.dumps({'id': rec_id}),mimetype='application/json')
    res.status_code = 200
    return res
@app.route('/question/<string:q_id>', methods=['GET'])
def get_question(q_id):
    """获取问题数据接口"""
    data = execute('select content from question where id=%s', (q_id,), True)
    if data:
        data = data['content']
    res = Response(json.dumps(json.loads(data),ensure_ascii=False),mimetype='application/json')
    res.status_code = 200
    return res

@app.route('/save', methods=['POST'])
def save_data():
    """保存数据接口"""
    data = request.get_json()
    print("保存的数据:", data)
    form_data = json.dumps(data.get('form_data'), ensure_ascii=False)
    question_id = data.get('question_id')
    current_index = data.get('current_index')
    uuid_id = uuid.uuid4().hex
    execute('''
        insert into answer (id, question_id,question_index,content,create_date) values(%s,%s,%s,%s,%s)
    ''', (uuid_id,question_id,current_index,form_data, datetime.datetime.now()),commit=True)
    res = Response(json.dumps({"status": "success", "message": "保存成功"}),mimetype='application/json')
    res.status_code = 200
    return res

@app.route('/result', methods=['GET'])
def get_result():
    """保存数据接口"""
    def datetime_serializer(obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        raise TypeError("Type not serializable")
    qid = request.args.get('question_id')
    res=execute('''
        select * from result where question_id=%s
    ''', (qid,), return_many=True)
    for i in res:
        i['mis_content']=json.loads(i['mis_content'])
    res = Response(json.dumps(res, ensure_ascii=False,default=datetime_serializer),mimetype='application/json')
    res.status_code = 200
    return res


@app.route('/commit', methods=['POST'])
def commit_data():
    """提交数据接口"""
    data = request.get_json()
    print("提交的数据:", data)
    save_data()
    question_id = data.get('question_id')
    res = execute('select content from question where id=%s', (question_id,), return_one=True)
    correct = json.loads(res['content'])
    res = execute('select content,question_index,create_date from answer where question_id=%s', (question_id,), return_many=True)
    total = 0
    mis = 0
    mistakes = []
    for i in res:
        s = json.loads(i['content'])
        q = correct[i['question_index']]
        ref = {c['label']:c['value'] for c in q}
        for k,v in s.items():
            total += 1
            if v != ref[k]:
                mis += 1
                mistakes.append({'key': f'{i["create_date"]}-{i["question_index"]}-{k}', 'mistake': v, 'correct': ref[k]})
    execute('insert into result (id, question_id, create_date, mis_content, total, mistake) values(%s,%s,%s,%s,%s,%s)', (
        uuid.uuid4().hex, question_id, datetime.datetime.now(), json.dumps(mistakes, ensure_ascii=False), total, mis
    ),commit=True)
    res =  Response(json.dumps({"total": "success", "message": "提交成功"}),mimetype='application/json')
    res.status_code = 200
    return res

if __name__ == '__main__':
    app.run(host='0.0.0.0',debug=True, port=5000)

